package com.comtrade.activities;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.comtrade.device.TestDevice;
import com.comtrade.device.TestDevice.RegistrationListener;
import com.comtrade.device.TestEquipment;
import com.comtrade.ilserver.tasks.Space;
import com.comtrade.ilserver.tasks.User;
import com.comtrade.map.MapFrame;
import com.comtrade.mathematics.BeaconRacun;
import com.comtrade.mathematics.Circle;
import com.dataart.android.devicehive.DeviceClass;
import com.dataart.android.devicehive.DeviceData;
import com.dataart.android.devicehive.Network;
import com.estimote.sdk.Beacon;
import com.estimote.sdk.BeaconManager;
import com.estimote.sdk.Region;
import com.example.beaconapk.R;

public class DeviceActivity extends Activity implements RegistrationListener,
		SensorEventListener {
	private static final String TAG = DeviceActivity.class.getSimpleName();

	public static final String EXTRAS_TARGET_ACTIVITY = "extrasTargetActivity";
	public static final String EXTRAS_BEACON = "extrasBeacon";
	private static final int REQUEST_ENABLE_BT = 1234;
	private static final Region ALL_ESTIMOTE_BEACONS_REGION = new Region("rid",
			null, null, null);

	private List<Beacon> listaBikonaSkeniranih;
	private NotificationManager notificationManager;
	PointF currnetPosition;

	private MapFrame mapframe;
	private BeaconManager beaconManager;
	private Vector<BeaconRacun> beacons;
	private List<Parameter> parameters = new LinkedList<Parameter>();
	private Matrix matrix;
	private float currentDegree = 0f;
	private SensorManager mSensorManager;
	private TestDevice device;
	private DeviceData deviceData;
	private Space sp;

	public static class Parameter {
		public final String name;
		public final float value;

		public Parameter(String name, float value) {
			this.name = name;
			this.value = value;
		}
	}

	Drawable image;

	String ilsSeverUri;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Setting up Content of Activity
		mapframe = new MapFrame(this);
		setContentView(mapframe);

		// Setting up DeviceHive
		parameters = new LinkedList<Parameter>();

		Intent i = getIntent();
		Log.d("SLIKA3", getIntent().getByteArrayExtra("image").toString());
		byte[] byteArray = getIntent().getByteArrayExtra("image");
		Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0,
				byteArray.length);
		Log.d("SLIKA2", bitmap.toString());
		Drawable drawablemap = new BitmapDrawable(getResources(), bitmap);

		final Space sp = (Space) i.getParcelableExtra("SPACE"); // .getExtras().get("SPACE");
		int width = sp.getSpacecoor().get(1).getX();
		int height = sp.getSpacecoor().get(1).getY();
		Toast.makeText(DeviceActivity.this, sp.getTitle(), Toast.LENGTH_SHORT)
				.show();
		Log.d("SLIKA", drawablemap.toString());
		mapframe.setMapImage(drawablemap, width, height);

		mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

		mapframe.setBeaconsList(sp.getBeacons());
		mapframe.SendBeaconsToTouchView();
		User u = (User) i.getParcelableExtra(User.EXTRA);
		Log.d("user", "" + i.getParcelableExtra(User.EXTRA));
		Network network = new Network(sp.getTitle(), "");
		DeviceClass deviceClass = new DeviceClass("Indoor location device",
				"1.1");
		deviceData = new DeviceData(u.getUuid(),
				"4D6B0A4A-CA77-4164-AAB0-52A7FE3DBD76", u.getFirstname() + " "
						+ u.getSurname(), DeviceData.DEVICE_STATUS_ONLINE,
				network, deviceClass);
		device = new TestDevice(this, deviceData, new TestEquipment());
		// mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

		// ...

		// Podesavanje iBeacon

		/*
		 * Porvera da li se nalazi u mapi beacon sa tom mac adresom ako se ne
		 * nalazi pravi novo polje u mapi sa tim kljucem i dodaje novi vektor sa
		 * daljinom inace ako nema barem 6 vrednosti upisanih za taj kljuc
		 * dodaje udaljenos u vektor else racuna prosek 6 vrednosti, stavlja u
		 * beaconDistances mapu i resetuje RSSI List
		 */

		beaconManager = new BeaconManager(this);

		beaconManager.setRangingListener(new BeaconManager.RangingListener() {
			@Override
			public void onBeaconsDiscovered(Region region,
					final List<Beacon> discoveredBeacons) {

				// Note that results are not delivered on UI thread.
				runOnUiThread(new Runnable() {
					@Override
					public void run() {
						Log.d("beaconManager Scanning", "started thread");
					}
				});

			}
		});

		/*
		 * beaconManager.setMonitoringListener(new MonitoringListener() {
		 * 
		 * @Override public void onExitedRegion(Region arg0) {
		 * 
		 * Toast.makeText(getApplicationContext(), "OUT",
		 * Toast.LENGTH_SHORT).show(); }
		 * 
		 * @Override public void onEnteredRegion(Region arg0, List<Beacon> arg1)
		 * {
		 * 
		 * } });
		 */

	}

	private void postNotification(String msg) {
		Notification.Builder notification = new Notification.Builder(this)
				.setSmallIcon(R.drawable.beacon_gray)
				.setContentTitle("iBeacon Proximity").setContentText(msg);
		notificationManager.notify(1, notification.build());
	}

	private void updateMap() {

		Vector<Circle> krive = new Vector<Circle>();
		for (int i = 0; i < beacons.size() - 1; i++) {
			for (int j = i + 1; j < beacons.size(); j++) {
				Circle krug = Circle.getTwoBeaconsCircle(beacons.elementAt(i),
						beacons.elementAt(j));
				if (krug != null) {
					krive.add(krug);
				} else {
					continue;
				}
			}

		}

		Vector<PointF> points = Circle.potential_points(beacons);

		final PointF tacka = Circle.kandidat(points);

		if (tacka != null && !Float.isNaN(tacka.x) && !Float.isNaN(tacka.y)) {
			runOnUiThread(new Runnable() {
				public void run() {
					if (tacka.x != currnetPosition.x
							|| tacka.y != currnetPosition.y) {
						parameters.clear();
						addParameter("x", tacka.x);
						addParameter("y", tacka.y);
						sendDeviceDataNotification();
						Log.d(TAG, "" + tacka.x + " " + tacka.y);
						mapframe.getDotView().setCoordinates(tacka.x * 100,
								tacka.y * 100);
					}

				}
			});

		}

	}

	private void postNotification(int id, String msg) {
		Notification.Builder notification = new Notification.Builder(this)
				.setSmallIcon(R.drawable.beacon_gray)
				.setContentTitle("iBeacon Proximity").setContentText(msg);

		notificationManager.notify(id, notification.build());
	}

	private void sendDeviceDataNotification() {

		HashMap<String, Object> parameters = paramsAsMap(this.parameters);
		device.getDeviceData().setData(parameters);
		device.registerDevice();
		Log.d(TAG, "" + device.getDeviceData().getData().toString());
	}

	private void connectToService() {
		beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
			@Override
			public void onServiceReady() {
				try {
					beaconManager.startRanging(ALL_ESTIMOTE_BEACONS_REGION);
					beaconManager.startMonitoring(ALL_ESTIMOTE_BEACONS_REGION);
				} catch (RemoteException e) {
					Toast.makeText(
							DeviceActivity.this,
							"Cannot start ranging, something terrible happened",
							Toast.LENGTH_LONG).show();
					Log.e(TAG, "Cannot start ranging", e);
				}
			}
		});
	}

	@Override
	protected void onStart() {
		super.onStart();

		// Check if device supports Bluetooth Low Energy.

		/*
		 * if (!beaconManager.hasBluetooth()) { Toast.makeText(this,
		 * "Device does not have Bluetooth Low Energy",
		 * Toast.LENGTH_LONG).show(); return; } /* // If Bluetooth is not
		 * enabled, let user enable it. if (!beaconManager.isBluetoothEnabled())
		 * { Intent enableBtIntent = new Intent(
		 * BluetoothAdapter.ACTION_REQUEST_ENABLE);
		 * startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } else {
		 * connectToService(); }
		 */
	}

	@Override
	protected void onResume() {
		super.onResume();

		mSensorManager.registerListener(this,
				mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
				SensorManager.SENSOR_DELAY_GAME);
		device.setApiEnpointUrl("http://147.91.204.220:8181/DeviceHiveJava/rest");
		device.addDeviceListener(this);
		if (!device.isRegistered()) {
			device.registerDevice();
		} else {
			device.startProcessingCommands();
		}

		// iBeacons

		// TODO: MapFrame set beacon Position

	}

	@Override
	protected void onPause() {
		super.onPause();
		mSensorManager.unregisterListener(this);
		if (isFinishing()) {
			device.unregisterDevice();
		}
	}

	@Override
	protected void onStop() {
		// iBeacons
		/*
		 * try { beaconManager.stopRanging(ALL_ESTIMOTE_BEACONS_REGION); } catch
		 * (RemoteException e) { Log.d(TAG, "Error while stopping ranging", e);
		 * }
		 */
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		device.removeDeviceListener(this);

		if (isFinishing()) {
			device.unregisterDevice();
		}
		// iBeacoons
		// beaconManager.disconnect();

		super.onDestroy();
	}

	/*
	 * ///////// DEVICE \\\\\\\\\\\
	 */

	@Override
	public void onDeviceRegistered() {

	}

	@Override
	public void onDeviceFailedToRegister() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		final AlertDialog dialog = builder
				.setTitle("Error")
				.setMessage("Failed to register device")
				.setPositiveButton("Retry",
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								device.registerDevice();
							}
						})
				.setNegativeButton("Cancel",
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								dialog.dismiss();
								finishActivity(0);
							}
						}).create();
		dialog.show();
	}

	protected void showDialog(String title, String message) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		final AlertDialog dialog = builder.setTitle(title).setMessage(message)
				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				}).create();
		dialog.show();
	}

	protected void showErrorDialog(String message) {
		showDialog("Error!", message);
	}

	private static final int SETTINGS_REQUEST_CODE = 0x01;

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == SETTINGS_REQUEST_CODE && resultCode == RESULT_OK) {
			Log.d(TAG, "Changed settings!");
			device.unregisterDevice();
			device.setApiEnpointUrl("http://147.91.204.220:8181/DeviceHiveJava/rest");
		}
	}

	public void addParameter(String name, float value) {
		this.parameters.add(new Parameter(name, value));
	}

	private static HashMap<String, Object> paramsAsMap(List<Parameter> params) {
		HashMap<String, Object> paramsMap = new HashMap<String, Object>();
		for (Parameter param : params) {
			paramsMap.put(param.name, param.value);
		}
		return paramsMap;
	}

	/*
	 * INIT FOR MENU
	 * 
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			Intent intent = new Intent(this, SettingsActivity.class);
			startActivity(intent);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		float degree = Math.round(event.values[0]);
		mapframe.getTouchView().rotate(degree, currentDegree);
		currentDegree = degree;
	}
}
